﻿#light

namespace Langexplr.SwfSupport

open System
open System.IO

type BitReader(baseReader:BinaryReader) = class
    let mutable bitPosition:int = -1
    let mutable currentByte:byte = byte(0)
    member this.ReadBits(n:int) =
       if (n > 8) then
          raise (new InvalidOperationException("could not read more than 8 bits at a time"))
       else
          if (bitPosition = -1) || (bitPosition = 8) || (bitPosition = 0)  then
             currentByte <- baseReader.ReadByte()          
             bitPosition <- n
             let mask = ((1 <<< n) - 1) in
                ((currentByte >>> (8 - n)) &&& byte(mask))             
          else
             let toReadInThisByte = if (n + bitPosition) >= 8 then 8 - bitPosition else n in
             let partial = (currentByte >>> (8 - (bitPosition + toReadInThisByte))) in
             let mask = ((1 <<< toReadInThisByte) - 1) in 
             let aResult = ((partial) &&& byte(mask)) in
             bitPosition <- bitPosition + toReadInThisByte
             if (n <> toReadInThisByte)  then
                (aResult ||| (this.ReadBits(n - toReadInThisByte) <<< toReadInThisByte))
             else
                 aResult                                        
end  



module Utils = begin



 let rec ReadingZeroString(startIndex:int,currentIndex:int,data : byte array) =
    if data.[currentIndex] = byte(0) then
       if (currentIndex - startIndex <> 0) then
         (System.Text.Encoding.UTF8.GetString(
                (Seq.skip startIndex data) |> 
                   Seq.take (currentIndex - startIndex) |>
                   Seq.toArray), currentIndex)
             
       else
         ("",currentIndex)
    else
       ReadingZeroString(startIndex,currentIndex+1,data)

 let ReadZeroString(startIndex:int,data : byte array) =  
    ReadingZeroString(startIndex,startIndex,data)
  

 let ReadTagStringGroup(startIndex:int,data :byte array) = 
       let numberOfSymbols = int16(data.[startIndex]) ||| (int16(data.[startIndex+1]) <<< 8)
     
       Seq.fold (fun (index,list) symbolNumber ->
                     let tagNumber = int16(data.[index]) ||| (int16(data.[index+1]) <<< 8)
                     let (nextString,nextIndex) = ReadZeroString(int(index)+2,data) in
                       (nextIndex+1,(nextString,tagNumber)::list)
                 ) (startIndex+2,[]) {int16(1)..numberOfSymbols}



 let rec ReadRectPart(bitReader:BitReader,blocksOf8Bits:int,finalBlock:int) =
   if (blocksOf8Bits <> 0) then
      let part = int(bitReader.ReadBits(8)) in
      ((part <<< (8*(blocksOf8Bits - 1) + finalBlock)) ||| 
         ReadRectPart(bitReader,blocksOf8Bits-1,finalBlock))
   else 
     if finalBlock <> 0 then
        int(bitReader.ReadBits(finalBlock))
     else
        0

 let ReadRect(reader:BinaryReader) = 
   let bitReader = BitReader(reader) in
   let nbits = int(bitReader.ReadBits(5)) in 
   let blocksOf8Bits = nbits / 8 in
   let final = nbits % 8 in
   ( ReadRectPart(bitReader,blocksOf8Bits,final),
     ReadRectPart(bitReader,blocksOf8Bits,final),
     ReadRectPart(bitReader,blocksOf8Bits,final),
     ReadRectPart(bitReader,blocksOf8Bits,final))

end



   
